`timescale 1ns / 1ps
/*
 Copyright 2020 Sean Xiao, jxzsxsp@qq.com
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

module exu_CSR
(
    input  sys_clk,
    input  i_SYSTEM,
    
    input  [ 31: 0 ] i_rs1_val,
    input  [ 4: 0 ]  i_rd_idx,
    input  [ 5: 0 ]  i_csr_instr,

    input  [ 11: 0 ] i_csr_addr,
    input  [ 31: 0 ] i_csr_imm,

    input  i_ext_irq,
    input  i_sft_irq,
    input  i_tmr_irq,
    
    input  i_irq_src,
    input  i_exp_src,
    input  [ 31: 0 ] i_exe_pc,
    input  [ 31: 0 ] i_ir,

    output [ 31: 0 ]   o_irq_pc,
    output [ 31: 0 ] o_mepc,
    
    input  i_mret_ena,
    
    output o_wr_dcsr_ena,
    output o_wr_dpc_ena,
    output o_wr_dscrh_ena,

    output [ 31: 0 ] o_dcause,
    input  [ 31: 0 ] i_dcsr_r,
    input  [ 31: 0 ] i_dpc_r,
    input  [ 31: 0 ] i_dscratch_r,

    input  i_EXE_vld,
    input  i_dbg_mode,
    input  i_dbg_stpcyl,

    output [ 31: 0 ] o_wr_csr_nxt,
    output [ 31: 0 ] o_csr_dpc_r,

    output o_rd_wen,
    output [ 4: 0 ] o_wb_rd_idx,
    output [ 31: 0 ] o_wb_data,

    output o_meie,
    output o_msie,
    output o_mtie,
    output o_glb_irq,

    input  rst_n
);

// i_csr_instr = {rv32i_csrrci, rv32i_csrrsi, rv32i_csrrwi,
//                rv32i_csrrc,  rv32i_csrrs,  rv32i_csrrw};

wire csr_wen  = i_EXE_vld & i_SYSTEM & (i_csr_addr[11:10] != 2'b11);
wire csr_rden = i_EXE_vld & i_SYSTEM;
wire [ 31: 0 ] w_csr_val;
reg  [ 31: 0 ] reg_csr_val;

always @ ( * )
begin
    reg_csr_val <= 32'b0;
    // reg_csr_wen<=1'b0;
    if ( i_SYSTEM & csr_wen )
    begin
        // csr_wen<=1'b1;
        case ( i_csr_instr )
            6'h01:
            begin
                reg_csr_val <= i_rs1_val; //rv32i_csrrw
            end
            6'h02:
            begin
                reg_csr_val <= i_rs1_val | w_csr_val;  //rv32i_csrrs
            end
            6'h04:
            begin
                reg_csr_val <= ( ~i_rs1_val ) & w_csr_val; //rv32i_csrrc
            end
            6'h08:
            begin
                reg_csr_val <= i_csr_imm; //rv32i_csrrwi
            end
            6'h10:
            begin
                reg_csr_val <= i_csr_imm | w_csr_val;  //rv32i_csrrsi
            end
            6'h20:
            begin
                reg_csr_val <= ( ~i_csr_imm ) & w_csr_val; //rv32i_csrrci
            end
            default: ;
        endcase
    end

end




csr_reg csr_reg_U
(
    .sys_clk        ( sys_clk ),

    .i_mret_ena     ( i_mret_ena ),

    .i_EXE_vld      ( i_EXE_vld ),
    .i_dbg_mode     ( i_dbg_mode ),
    .i_dbg_stpcyl   ( i_dbg_stpcyl ),

    .i_ext_irq      ( i_ext_irq ),
    .i_sft_irq      ( i_sft_irq ),
    .i_tmr_irq      ( i_tmr_irq ),
//    .i_irq_src          ( i_irq_src ),
    .i_irq_src      ( i_irq_src & o_glb_irq),
    
    .i_exp_src      ( i_exp_src ),
    .i_exe_pc       ( i_exe_pc ),
    .i_ir           ( i_ir ),

    .o_irq_pc       ( o_irq_pc ),
    .o_mepc         ( o_mepc ),
    
    .o_wr_dcsr_ena  ( o_wr_dcsr_ena ),
    .o_wr_dpc_ena   ( o_wr_dpc_ena ),
    .o_wr_dscrh_ena ( o_wr_dscrh_ena ),
    
    .i_dcsr         ( i_dcsr_r ),
    .i_dpc          ( i_dpc_r ),
    .i_dscratch     ( i_dscratch_r ),
    
    .i_csr_rden     ( csr_rden ),
    .i_csr_addr     ( i_csr_addr ),
    .i_csr_val      ( reg_csr_val ),
    .i_csr_wen      ( csr_wen ),
    .o_csr_val      ( w_csr_val ),

    .o_meie         ( o_meie ),
    .o_msie         ( o_msie ),
    .o_mtie         ( o_mtie ),
    .o_glb_irq      ( o_glb_irq ),

    .rst_n          ( rst_n )
);


//assign cause_ena = mepc_ena;
assign o_csr_dpc_r = i_dpc_r;
assign o_wr_csr_nxt = reg_csr_val;

assign o_wb_rd_idx = i_rd_idx;
assign o_wb_data = w_csr_val;
assign o_rd_wen = i_SYSTEM;

endmodule
